import uuid

import config
from util import DB
from loglines import loglines
from loglines import ApacheLogLine




class SessionStore:
    """ a class for storing session with buffer"""
    #dict for storing sessions
    #key - session id (a uuid)
    #value - a set of log lines
    sessions = {}   
    
    def __init__(self):     
        self.buf_size = config.session_bufsize
    
    #to code. flush sessions???????? which to save????
    def setDefault(self, sess_key, lines):
        if len(self.sessions) >= self.buf_size:
            self.flushSessions()
            #to code .save sessions whose last line's time is timeout
        return self.sessions.setdefault(sess_key, lines)
    
    def addline(self, sess_key, line):
        if len(self.sessions) >= self.buf_size:
            self.flushSessions(line.date)
        self.sessions.setdefault(sess_key, []).append(line)
    
    #flush sessions,which is nothing about with current log line, into database     
    def flushSessions(self, cur_line_time):
        #initialize db connection
        conn = DB.getConn()
        cur = conn.cursor()
        cur.execute("set names GBK")
        
        fresh_sessions = {}
        for session in self.sessions.items():
            if (cur_line_time - session[1][len(session[1]) - 1].date).seconds > config.session_timeout:
                for l in session[1]:
                    #insert every line of session into database
                    sql_detail = "insert into detailsession(line_no,sess_key,ip,uid,"+\
                             "user_agent,time,http_method,url,resp_code,bytes) "+\
                            "values(%s,'%s','inet_aton(%s)','%s','%s','%s','%s','%s','%s','%s')" % ('null', session[0], l.ip,
                            l.http_user, l.ident, l.date, l.http_method, l.url, l.http_response_code, l.http_response_size)
                    sql_simple = "insert into simplesession(sess_key,ip,uid,url,urlid,time)"+\
                                 " values('%s','inet_aton(%s)','%s','%s',%d,'%s')" % (session[0], l.ip, l.http_user, l.url,uuid.uuid3(uuid.NAMESPACE_URL, l.url).hex,l.date)
                    #print sql_detail
                    #cur.execute(sql_detail)
                    print sql_simple
                    cur.execute(sql_simple)
            else:
                fresh_sessions.setdefault(session[0], session[1])
        self.sessions = fresh_sessions
        #close db connection
        conn.commit()
        cur.close()
        conn.close()
        
        
    #flush sessions,which is nothing about with current log line, into database     
    def flushAllSessions(self):
        #initialize db connection
        conn = DB.getConn()
        cur = conn.cursor()
        cur.execute("set names GBK")
        for session in self.sessions.items():
            for l in session[1]:
                #insert every line of session into database
                sql_detail = "insert into detailsession(line_no,sess_key,ip,uid,"+\
                             "user_agent,time,http_method,url,resp_code,bytes) "+\
                            "values(%s,'%s','inet_aton(%s)','%s','%s','%s','%s','%s','%s','%s')" % ('null', session[0], l.ip,
                            l.http_user, l.ident, l.date, l.http_method, l.url, l.http_response_code, l.http_response_size)
                sql_simple = "insert into simplesession(sess_key,ip,uid,url,urlid,time)"+\
                                 " values('%s',inet_aton('%s'),'%s','%s','%s','%s')" % (session[0], l.ip, l.http_user, l.url, uuid.uuid3(uuid.NAMESPACE_URL, l.url).hex,l.date)
                #print sql_detail
                #cur.execute(sql_detail)
                print sql_simple
                cur.execute(sql_simple)
        #close db connection
        conn.commit()
        cur.close()
        conn.close()
        
class LogParser:
    """ class to parse log line from myf's db"""
    
    sessions = SessionStore()
    
    sessCount = 0
    
    def __init__(self, lines):
        self.ignored_postfix = config.ignored_postfix
        self.ignored_method = config.ignored_method
        self.lines = lines
        
    def parse(self):
        """The very function to clean data,extract sessions"""
        #dictionary containing tuples (time, unique id) for IPs
        #key - IP
        #value - (time of last request, unique id)
        last_ip = {}
        
        #dictionary for storing the last http_response_code for every session
        #key - session id
        #value - last http_response_code for that session
        last_session_http_code = {}
        
        for line in self.lines:           
            
            #filter job used only in test by yyh...
#            if self.filter(line):
#                continue
            
#            # if last_ip buffer is full,take out timeout ip
#            if len(last_ip) >= config.last_ip_bufsize:
#                last_ip = filter(lambda i:(line.date - i[1]).seconds > config.session_timeout, last_ip.items())
#            
            last_ip.setdefault(line.ip, (line.date, uuid.uuid1().hex))
            (last_time_for_ip, last_session_for_ip) = last_ip[line.ip]
            
            delta = line.date - last_time_for_ip
            if delta.seconds > config.session_timeout:
                sess_key = uuid.uuid1().hex
            else:
                sess_key = last_session_for_ip
                
            #if last request in this session was met with http code 302, then
            #this line is probably a redirect and should be discarded
#            code = last_session_http_code.get(sess_key, 0)
#            if int(code) == 302 and  int(line.http_response_code) == 200 and delta.seconds < 2:
#                continue 
            
            #to code
            last_ip[line.ip] = (line.date,sess_key)
            
            #add last session http code
            last_session_http_code.setdefault(sess_key, line.http_response_code)
            
            #add line to sessions dict
            #if session doesn't exist in sessions,then initialize it
            self.sessions.addline(sess_key, line)
            #self.sessions.setDefault(sess_key,[]).append(line)
            
            self.sessCount += 1
            
        self.sessions.flushAllSessions()  
    
    #function to filter useless log line like pics and robots,etc.
    #filter type and ip blacklist are configurable
    #
    #   notice: only use in test by yyh...
    def filter(self, line):
        result = False
       
#        if self.ip_blacklist.count(line.ip) > 0:
#            return True
        
        #no pics and others
        for postfix in self.ignored_postfix:
            result = result or line.url.find(postfix) != -1
        #no HTTP OPTIONS
        for method in self.ignored_method:
            result or line.http_method.find(method) != -1
        
        return result


def startSessIdentify(tblname=config.purged_log_tbname):
    print "start session indentifying..."
    logline = loglines(tblname)
    cur=DB.getCur()
    cur.execute("truncate simplesession;")
    cur.execute("truncate detailsession;")
    parser = LogParser(logline)
    parser.parse()
    print "parsing done!"        


if __name__ =="__main__":
    startSessIdentify()
        
